#pragma once
// 本文件将编译和运行整合到一起
#include "complie.hpp"
#include "run.hpp"

#include <jsoncpp/json/json.h>

namespace ns_CR
{
    using namespace ns_complier;
    using namespace ns_runner;
    /***************************************
     * 输入:
     * code： 用户提交的代码
     * input: 用户给自己提交的代码对应的输入，不做处理
     * cpu_limit: 时间要求
     * mem_limit: 空间要求
     *
     * 输出:
     * 必填
     * status: 状态码
     * reason: 请求结果
     * 选填：
     * stdout: 我的程序运行完的结果
     * stderr: 我的程序运行完的错误结果
     *
     * 参数：
     * in_json: {"code": "#include...", "input": "","cpu_limit":1, "mem_limit":10240}
     * out_json: {"status":"0", "reason":"","stdout":"","stderr":"",}
     * ************************************/
    class ComplieAndRun
    {
    private:
        static void RemoveTempFile(const std::string &file_name)
        {
            // 不确定有多少个临时文件要删除，但可以确定要删除文件的每一个文件名
            std::string _src = PathUtil::Src(file_name);
            if (FileUtil::isFileExist(_src))
                ::unlink(_src.c_str());
            std::string _cmp_err = PathUtil::CmErr(file_name);
            if (FileUtil::isFileExist(_cmp_err))
                ::unlink(_cmp_err.c_str());
            std::string _execut = PathUtil::Exe(file_name);
            if (FileUtil::isFileExist(_execut))
                ::unlink(_execut.c_str());
            std::string _stdin = PathUtil::Stdin(file_name);
            if (FileUtil::isFileExist(_stdin))
                ::unlink(_stdin.c_str());
            std::string _stdout = PathUtil::Stdout(file_name);
            if (FileUtil::isFileExist(_stdout))
                ::unlink(_stdout.c_str());
            std::string _stderr = PathUtil::Err(file_name);
            if (FileUtil::isFileExist(_stderr))
                ::unlink(_stderr.c_str());
        }

    public:
        static std::string CodeToString(int code, std::string &_filename)
        {
            /**
             * code
             * < 0 ：非运行出错
             * > 0 ：运行时出异常
             * ==0 成功运行
             *
             */
            std::string desc;
            switch (code)
            {
            case 0:
                desc = "代码编译运行成功";
                break;
            case -1:
                desc = "提交的代码为空";
                break;
            case -2:
                desc = "未知错误，可能是写入文件失败";
                break;
            case -3:
                // desc = FileUtil::ReadFile(PathUtil::CmErr(_filename));
                FileUtil::ReadFile((PathUtil::CmErr(_filename)), &desc, true);
                break;
            case -4:
                desc = "运行出错";
                break;
            case SIGABRT:
                desc = "内存超出使用范围";
                break;
            case SIGXCPU:
                desc = "cpu使用超时";
                break;
            default:
                desc = "未知错误,status_code等于" + std::to_string(code);
                break;
            }
            return desc;
        }
        // 对于一个整合好的函数，它处理一个从下层传上来的网络字节流，输出的也应该是一个字符串
        static void Start(const std::string &in_json, std::string *out_json)
        {
            // 把网络字节流反序列化
            Json::Value in_string;
            // 要用到Json中的反序列中间类
            Json::Reader reader;
            reader.parse(in_json, in_string);
            //{"code":"#include .....",}
            std::string code = in_string["code"].asString();
            std::string input = in_string["input"].asString();
            int cpu_limit = in_string["cpu_limit"].asInt();
            int mem_limit = in_string["mem_limit"].asInt();

            // 准备out_json，这个过程是序列化
            Json::Value out_string;
            // 定义可能的全部变量
            int status_code = 0; // 用于保存执行结果

            // 对于解析出来代码的处理，形成一个SRC文件，但是有可能多个用户在做同一道题，所以要保证形成的SRC
            // 文件是唯一的
            std::string filename = FileUtil::UniqueFileName();

            int run_result = 0;

            // 做一个小判断
            if (code.size() == 0)
            {
                status_code = -1;
                goto END;
            }

            // 这里拿到了文件名，就可以生成SRC文件了，方法在comm中有
            // 有了文件名，有了代码，就要报代码写入文件
            if (!FileUtil::WriteFile(PathUtil::Src(filename), code))
            {
                status_code = -2;
                goto END;
            }
            // 编译代码
            if (!Complier::Complie(filename))
            {
                status_code = -3;
                goto END;
            }
            run_result = Runner::Run(filename, cpu_limit, mem_limit); // 运行结果
            if (run_result < 0)
            {
                status_code = -4;
                goto END;
            }
            // 出异常
            if (run_result > 0)
            {
                status_code = run_result;
                goto END;
            }

        END:
            out_string["status"] = status_code;
            out_string["reason"] = CodeToString(status_code, filename);
            if (status_code == 0)
            {
                // 整个过程全部成功
                std::string _stdout;
                FileUtil::ReadFile(PathUtil::Stdout(filename), &_stdout, true);
                out_string["stdout"] = _stdout;

                std::string _stderr;
                FileUtil::ReadFile(PathUtil::Err(filename), &_stderr, true);
                out_string["stderr"] = _stderr;
            }
            // 将out_string序列化成Json字符串
            Json::FastWriter writer;
            *out_json = writer.write(out_string);
            RemoveTempFile(filename);
        }
    };
}